home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / base / 003-desktop.lzm / usr / sbin / cups-genppdupdate.5.0 < prev    next >
Encoding:
Text File  |  2008-03-15  |  20.8 KB  |  775 lines

  1. #! /usr/bin/perl -w
  2. # $Id: cups-genppdupdate.in,v 1.25.8.4 2007/12/29 20:42:25 rlk Exp $
  3. # Update CUPS PPDs for Gutenprint queues.
  4. # Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org)
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2, or (at your option)
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  
  20. use strict;
  21. use Getopt::Std;
  22. use Fcntl qw(:mode);
  23. use File::Temp qw(:POSIX);
  24. use File::Copy qw(mv);
  25.  
  26. sub parse_options ();
  27. sub update_ppd ($); # Original PPD filename
  28. sub get_ppd_contents ($$$$$); # Return contents of desired PPD
  29. sub find_ppd ($$$$); # Gutenprint Filename, driver, language (e.g. en, sv),
  30.              # region (e.g. GB, DE)
  31. sub get_default_types (*); # Source PPD FH
  32. sub get_defaults (*); # Source PPD FH
  33. sub get_options (*\%); # Source PPD FH, default_types hash ref
  34.  
  35. our $opt_d; # Debug mode
  36. our $opt_h; # Help
  37. our $opt_n; # No action
  38. our $opt_q; # Quiet mode
  39. our $opt_s; # Source PPD location
  40. our $opt_p; # New PPD location
  41. our $opt_P; # PPD generator location
  42. our $opt_v; # Verbose mode
  43. our $opt_N; # Don't update PPD file options
  44. our $opt_o; # Output directory
  45.  
  46. my $debug = 0;
  47. my $verbose = 0;   # Verbose output
  48. if ($debug) {
  49.     $verbose = 1;
  50. }
  51. my $quiet = 0;     # No output
  52. my $no_action = 0; # Don't output files
  53. my $reset_defaults = 0;        # Reset options to default settings
  54. my $version = "5.0";
  55. my $micro_version = "5.0.2";
  56. my $use_static_ppd = "no";
  57.  
  58. my $ppd_dir = "/etc/cups/ppd"; # Location of in-use CUPS PPDs
  59. my $ppd_root_dir = "/usr/share/cups/model";
  60. my $ppd_base_dir = "$ppd_root_dir/gutenprint/$version"; # Available PPDs
  61. my $ppd_out_dir = "";        # By default output into source directory
  62. my $gzext = ".gz";
  63. my $updated_ppd_count = 0;
  64. my $exit_after_parse_args = 0;
  65.  
  66. my $serverdir = "/usr/lib/cups";
  67. my $driver_bin = "$serverdir/driver/gutenprint.$version";
  68. my $driver_version = `$driver_bin VERSION`;
  69. chomp $driver_version;
  70.  
  71. $Getopt::Std::STANDARD_HELP_VERSION = 1;
  72.  
  73. $Getopt::Std::STANDARD_HELP_VERSION = 1;
  74.  
  75. my @ppd_files; # A list of in-use Gutenprint PPD files
  76.  
  77. # Used to convert a language name to its two letter code
  78. my %languagemappings = (
  79.             "chinese"    => "cn",
  80.             "danish"     => "da",
  81.             "dutch"      => "nl",
  82.             "english"    => "en",
  83.             "finnish"    => "fi",
  84.             "french"     => "fr",
  85.             "german"     => "de",
  86.             "greek"      => "el",
  87.             "hungarian"  => "hu",
  88.             "italian"    => "it",
  89.             "japanese"   => "jp",
  90.             "norwegian"  => "no",
  91.             "polish"     => "pl",
  92.             "portuguese" => "pt",
  93.             "russian"    => "ru",
  94.             "slovak"     => "sk",
  95.             "spanish"    => "es",
  96.             "swedish"    => "sv",
  97.             "turkish"    => "tr"
  98. );
  99.  
  100.  
  101. # Check command-line options...
  102.  
  103. parse_options();
  104.  
  105.  
  106. # Set a secure umask...
  107.  
  108. umask 0177;
  109.  
  110.  
  111. # Find all in-use Gutenprint PPD files...
  112.  
  113. my @ppdglob;
  114. if (@ARGV) {
  115.     my $f;
  116.     foreach $f (@ARGV) {
  117.     if (-f $f and ($f =~ /\.ppd$/i or $f =~ /\//)) {
  118.         if (-f $f) {
  119.         push @ppdglob, $f;
  120.         } else {
  121.         print STDERR "Cannot find file $f\n";
  122.         }
  123.     } elsif (-f "$ppd_dir/$f" or
  124.          -f "$ppd_dir/$f.ppd" or
  125.          -f "$ppd_dir/$f.PPD") {
  126.         if (-f "$ppd_dir/$f") {
  127.         push @ppdglob, "$ppd_dir/$f";
  128.         }
  129.         if (-f "$ppd_dir/$f.ppd") {
  130.         push @ppdglob, "$ppd_dir/$f.ppd";
  131.         }
  132.         if (-f "$ppd_dir/$f.PPD") {
  133.         push @ppdglob, "$ppd_dir/$f.PPD";
  134.         }
  135.     }  else {
  136.         print STDERR "Cannot find file $ppd_dir/$f, $ppd_dir/$f.ppd, or $ppd_dir/$f.PPD\n";
  137.     }
  138.     }
  139. } else {
  140.     @ppdglob = glob("$ppd_dir/*.{ppd,PPD}");
  141. }
  142. my $ppdlist = join ' ', @ppdglob;
  143. if (@ppdglob) {
  144.     open PPDFILES, '-|', 'egrep', '-i', '-l', 'Gutenprint|Gimp-Print', @ppdglob or die "can't grep $ppdlist: $!";
  145.     while (<PPDFILES>) {
  146.     chomp;
  147.     push @ppd_files,  $_;
  148.     }
  149.     if (@ppd_files) {
  150.     open PPDFILES, '-|', 'egrep', '-i', '-L', 'Foomatic', @ppd_files or die "can't grep $ppdlist: $!";
  151.     @ppd_files = ();
  152.     while (<PPDFILES>) {
  153.         chomp;
  154.         push @ppd_files,  $_;
  155.     }
  156.     close PPDFILES or ($! == 0) or die "can't close grep pipe: $!";
  157.     }
  158. }
  159.  
  160.  
  161. # Exit if there are not files to update...
  162.  
  163. if (!@ppd_files) {
  164.     print STDOUT "No Gutenprint PPD files to update.\n";
  165.     exit (0);
  166. }
  167.  
  168. # Update each of the Gutenprint PPDs, where possible...
  169.  
  170. foreach (@ppd_files) {
  171.     $updated_ppd_count += update_ppd($_);
  172.  
  173. }
  174.  
  175. if (!$quiet || $verbose) {
  176.     if ($updated_ppd_count > 0) {
  177.     my $plural = "";
  178.     if ($updated_ppd_count != 1) {
  179.         $plural = "s";
  180.     }
  181.     print STDOUT "Updated $updated_ppd_count PPD file${plural}.  Restart cupsd for the changes to take effect.\n";
  182.     exit (0);
  183.     } else {
  184.     if ($no_action) {
  185.         print STDOUT "Did not update any PPD files\n";
  186.     } else {
  187.         print STDOUT "Failed to update any PPD files\n";
  188.     }
  189.     exit (0);
  190.     }
  191. }
  192.  
  193. sub HELP_MESSAGE($;$$$) {
  194.     my ($fh) = @_;
  195.     print $fh "Usage: $0 [OPTION]... [PPD_FILE]...\n";
  196.     print $fh "Update CUPS+Gutenprint PPD files.\n\n";
  197.     print $fh "  -d flags    Enable debugging\n";
  198.     print $fh "  -h          Display this help text\n";
  199.     print $fh "  -n          No-action.  Don't overwrite any PPD files.\n";
  200.     print $fh "  -q          Quiet mode.  No messages except errors.\n";
  201.     print $fh "  -s ppd_dir  Use ppd_dir as the source PPD directory.\n";
  202.     print $fh "  -p ppd_dir  Update PPD files in ppd_dir.\n";
  203.     print $fh "  -P driver   Use the specified driver binary to generate PPD files.\n";
  204.     print $fh "  -v          Verbose messages.\n";
  205.     print $fh "  -N          Reset options to defaults.\n";
  206.     print $fh "  -o out_dir  Output PPD files to out_dir.\n";
  207.     exit(0);
  208. }
  209.  
  210. # Getopt::Std calls VERSION_MESSAGE followed by HELP_MESSAGE if --help
  211. # is passed.  If --version is passed, it calls only VERSION_MESSAGE.
  212. # So we have to make sure to exit, but we want to allow --help to
  213. # print out the help message.
  214. sub VERSION_MESSAGE($;$$$) {
  215.     my ($fh) = @_;
  216.     print "cups-genppdupdate from Gutenprint $micro_version\n";
  217.     $exit_after_parse_args = 1;
  218. }
  219.  
  220. sub help() {
  221.     HELP_MESSAGE(\*STDOUT);
  222. }
  223.  
  224. sub parse_options () {
  225.     if (!getopts('d:hnqs:vNo:p:P:')) {
  226.     help();
  227.     }
  228.     if ($opt_n) {
  229.     $no_action = 1;
  230.     }
  231.     if ($opt_d) {
  232.     $debug = $opt_d;
  233.     }
  234.     if ($opt_s) {
  235.     if (-d $opt_s) {
  236.         $ppd_base_dir = "$opt_s";
  237.     }
  238.     else {
  239.         die "$opt_s: invalid directory: $!\n";
  240.     }
  241.     }
  242.     if ($opt_p) {
  243.     if (-d $opt_p) {
  244.         $ppd_dir = "$opt_p";
  245.     }
  246.     else {
  247.         die "$opt_p: invalid directory: $!\n";
  248.     }
  249.     }
  250.     if ($opt_P) {
  251.     if (-x $opt_P) {
  252.         $driver_bin = "$opt_P";
  253.     }
  254.     else {
  255.         die "$opt_P: invalid executable: $!\n";
  256.     }
  257.     }
  258.     if ($opt_v) {
  259.     $verbose = 1;
  260.     $quiet = 0;
  261.     }
  262.     if ($opt_q) {
  263.     $verbose = 0;
  264.     $quiet = 1;
  265.     }
  266.     if ($opt_N) {
  267.     $reset_defaults = 1;
  268.     }
  269.     if ($opt_o) {
  270.     if (-d $opt_o) {
  271.         $ppd_out_dir = "$opt_o";
  272.     }
  273.     else {
  274.         die "$opt_o: invalid directory: $!\n";
  275.     }
  276.     }
  277.     if ($opt_h) {
  278.     help();
  279.     }
  280.     if ($exit_after_parse_args) {
  281.     exit(0);
  282.     }
  283. }
  284.  
  285. sub get_ppd_contents($$$$$) {
  286.     my ($ppd_source_filename, $filename, $driver, $locale, $region) = @_;
  287.  
  288.     my $source_data;
  289.     my ($new_ppd_filename);
  290.  
  291.     if ($use_static_ppd eq "no" && $driver_version eq "5.0.2") {
  292.     my ($simplified);
  293.     if ($filename =~ m,.*/([^/]*)(.sim)(.ppd)?(.gz)?$,) {
  294.         $simplified = "simple";
  295.     } else {
  296.         $simplified = "expert";
  297.     }
  298.     my ($url);
  299.     my (@url_list);
  300.     if ($locale) {
  301.         if ($region) {
  302.         push @url_list, "gutenprint.$version://$driver/$simplified/${locale}_${region}";
  303.         }
  304.         push @url_list, "gutenprint.$version://$driver/$simplified/${locale}";
  305.     }
  306.     push @url_list, "gutenprint.$version://$driver/$simplified";
  307.     foreach $url (@url_list) {
  308.         $new_ppd_filename = $url;
  309.         if ($debug & 8) {
  310.         print "Trying $driver_bin cat $url for $driver, $simplified, $locale, $region\n";
  311.         }
  312.         if (open PPD, "$driver_bin cat $url 2>/dev/null |") {
  313.         while (<PPD>) {
  314.             $source_data .= $_;
  315.         }
  316.         close PPD;
  317.         if ($source_data) {
  318.             return ( $new_ppd_filename, $source_data );
  319.         }
  320.         }
  321.     }
  322.     # Otherwise fall through and try to find a static PPD
  323.     }
  324.  
  325.     # Search for a PPD matching our criteria...
  326.  
  327.     $new_ppd_filename = find_ppd($filename, $driver, $locale, $region);
  328.     if (!defined($new_ppd_filename)) {
  329.         # There wasn't a valid source PPD file, so give up.
  330.         print STDERR "$ppd_source_filename: no valid candidate for replacement.  Skipping\n";
  331.         print STDERR "$ppd_source_filename: please upgrade this PPD manually\n";
  332.     return ("", 0);
  333.     }
  334.     if ($debug & 1) {
  335.     print "Candidate PPD: $new_ppd_filename\n";
  336.     }
  337.  
  338.     my $suffix = "\\" . $gzext; # Add '\', so m// matches the '.'.
  339.     if ($new_ppd_filename =~ m/.gz$/) { # Decompress input buffer
  340.     open GZIN, "gunzip -c $new_ppd_filename |"
  341.         or die "$_: can't open for decompression: $!";
  342.     while (<GZIN>) {
  343.         $source_data .= $_;
  344.     }
  345.     close GZIN;
  346.     } else {
  347.     open SOURCE, $new_ppd_filename
  348.         or die "$new_ppd_filename: can't open source file: $!";
  349.     binmode SOURCE;
  350.     my $source_size = (stat(SOURCE))[7];
  351.     read (SOURCE, $source_data, $source_size)
  352.         or die "$new_ppd_filename: error reading source: $!";
  353.     close SOURCE or die "$new_ppd_filename: can't close file: $!";
  354.     }
  355.     return ( $new_ppd_filename, $source_data );
  356. }
  357.  
  358. # Update the named PPD file.
  359. sub update_ppd ($) {
  360.     my $ppd_source_filename = $_;
  361.     my $ppd_dest_filename = $ppd_source_filename;
  362.     if ($ppd_out_dir) {
  363.     $ppd_dest_filename =~ s;(.*)/([^/]+);$2;;
  364.     $ppd_dest_filename = "$ppd_out_dir/$ppd_dest_filename";
  365.     }
  366.  
  367.     open ORIG, $_ or die "$_: can't open PPD file: $!";
  368.     seek (ORIG, 0, 0) or die "can't seek to start of PPD file";
  369.     my @orig_metadata = stat(ORIG);
  370.     if ($debug & 1) {
  371.     print "Source Filename: $ppd_source_filename\n";
  372.     }
  373.     my ($filename) = "";
  374.     my ($driver) = "";
  375.     my ($gutenprintdriver) = "";
  376.     my ($locale) = "";
  377.     my ($lingo) = "";
  378.     my ($region) = "";
  379.     my ($valid) = 0;
  380.     while (<ORIG>) {
  381.     if (/\*StpLocale:/) {
  382.         ($locale) = m/^\*StpLocale:\s\"*(.*)\"$/;
  383.         $valid = 1;
  384.     }
  385.     if (/\*LanguageVersion/) {
  386.         ($lingo) = m/^\*LanguageVersion:\s*(.*)$/;
  387.     }
  388.     if (/^\*StpDriverName:/ ) {
  389.         ($driver) = m/^\*StpDriverName:\s*\"(.*)\"$/;
  390.         $valid = 1;
  391.     }
  392.     if (/\*%End of / && $driver eq "") {
  393.         ($driver) = m/^\*%End of\s*(.*).ppd$/;
  394.     }
  395.     if (/^\*StpPPDLocation:/ ) {
  396.         ($filename) = m/^\*StpPPDLocation:\s*\"(.*)\"$/;
  397.         $valid = 1;
  398.     }
  399.     if (/^\*%Gutenprint Filename:/) {
  400.         $valid = 1;
  401.     }
  402.     }
  403.     if (! $valid) {
  404.     print STDERR "$ppd_source_filename: this PPD file cannot be upgraded automatically (only files based on Gutenprint 5.0.0 and newer can be)\n";
  405.     return 0;
  406.     }
  407.     if ($debug & 2) {
  408.     print "Gutenprint Filename: $filename\n";
  409.     print "Locale: $locale\n";
  410.     print "Language: $lingo\n";
  411.     print "Driver: $driver\n";
  412.     }
  413.     if ($locale) {
  414.     # Split into the language and territory.
  415.     ($locale, $region) = split(/-/, $locale);
  416.     } else {
  417.     # Split into the language and territory.
  418.     ($locale, $region) = split(/-/, $lingo);
  419.     # Convert language into language code.
  420.     $locale = $languagemappings{"\L$lingo"};
  421.     if (!defined($locale)) {
  422.         $locale = "C"; # Fallback if there isn't one.
  423.     }
  424.     }
  425.     if (! defined($region)) {
  426.     $region = "";
  427.     }
  428.     if ($debug & 2) {
  429.     print "Base Locale: $locale\n";
  430.     print "Region: $region\n";
  431.     }
  432.  
  433.     # Read in the new PPD, decompressing it if needed...
  434.  
  435.     my ($new_ppd_filename, $source_data) =
  436.     get_ppd_contents($ppd_source_filename, $filename,
  437.              $driver, $locale, $region);
  438.  
  439.     if (! $source_data) {
  440.     print "Unable to retrieve PPD file!\n";
  441.     return 0;
  442.     }
  443.  
  444.     # Save new PPD in a temporary file, for processing...
  445.  
  446.     my($tmpfile, $tmpfilename) = tmpnam();
  447.     unlink $tmpfilename or warn "can't unlink temporary file $tmpfile: $!\n";
  448.     print $tmpfile $source_data;
  449.  
  450.  
  451.  
  452.  
  453.     # Extract the default values from the original PPD...
  454.  
  455.     my %orig_default_types = get_default_types(ORIG);
  456.     my %new_default_types = get_default_types($tmpfile);
  457.     my %defaults = get_defaults(ORIG);
  458.     my %options = get_options($tmpfile, %new_default_types);
  459.     my %resolution_map = get_resolution_map($tmpfile);
  460.  
  461.  
  462.     # Close original and temporary files...
  463.  
  464.     if (! close ORIG) {
  465.     print "$_: can't close file: $!\n";
  466.     return 0;
  467.     }
  468.     if (! close $tmpfile) {
  469.     print "can't close temporary file $tmpfile: $!\n";
  470.     return 0;
  471.     }
  472.  
  473.  
  474.     if ($debug & 4) {
  475.     print "Options (Old->New Default Type):\n";
  476.     foreach (sort keys %options) {
  477.         my ($old_type) = $orig_default_types{$_};
  478.         my ($new_type) = $new_default_types{$_};
  479.         if (! defined($old_type)) {
  480.         $old_type = '(New)';
  481.         }
  482.         if ($old_type ne $new_type) {
  483.         print "  $_ ($old_type -> $new_type) :  ";
  484.         } else {
  485.         print "  $_ ($new_type) :  ";
  486.         }
  487.         my ($def) = $defaults{"Default$_"};
  488.         foreach my $opt (@{$options{$_}}) {
  489.         if (defined $def && $def eq $opt) {
  490.             print "*";
  491.         }
  492.         print "$opt ";
  493.         }
  494.         print "\n";
  495.     }
  496.     if (keys %resolution_map) {
  497.         print "Resolution Map:\n";
  498.         foreach (sort keys %resolution_map) {
  499.         print "$_: $resolution_map{$_}\n";
  500.         }
  501.     }
  502.     print "Non-UI Defaults:\n";
  503.     foreach (sort keys %defaults) {
  504.         my ($xkey) = $_;
  505.         $xkey =~ s/^Default//;
  506.         if (! defined ($options{$xkey})) {
  507.         print "  $_: $defaults{$_}\n";
  508.         }
  509.     }
  510.     print "Default Types of dropped options:\n";
  511.     foreach (sort keys %orig_default_types) {
  512.         if (! defined($options{$_})) {
  513.         print "  $_: $orig_default_types{$_}\n";
  514.         }
  515.     }
  516.     }
  517.  
  518.     if ($no_action) {
  519.     if (!$quiet || $verbose) {
  520.         if ($ppd_dest_filename eq $ppd_source_filename) {
  521.         print STDOUT "Would update $ppd_source_filename using $new_ppd_filename\n";
  522.         } else {
  523.         print STDOUT "Would update $ppd_source_filename to $ppd_dest_filename using $new_ppd_filename\n";
  524.         }
  525.     }
  526.     return 0;
  527.     }    
  528.  
  529.     if  (! $reset_defaults) {
  530.     # Update source buffer with old defaults...
  531.  
  532.     # Loop through each default in turn.
  533. default_loop:
  534.     foreach my $default_option (sort keys %defaults) {
  535.         my $option;
  536.         ($option = $default_option) =~ s/Default//; # Strip off `Default'
  537.         # Check method is valid
  538.         my $orig_method = $orig_default_types{$option};
  539.         my $new_method = $new_default_types{$option};
  540.         if ((!defined($orig_method) || !defined($new_method)) ||
  541.         $orig_method ne $new_method) {
  542.         next;
  543.         }
  544.         if ($new_method eq "PickOne") {
  545.         # Check the old setting is valid
  546.         foreach my $opt (@{$options{$option}}) {
  547.             my $def_option = $defaults{$default_option};
  548.             if (($def_option eq $opt) ||
  549.             ($option eq "Resolution" &&
  550.              (defined $resolution_map{$defaults{$default_option}}) &&
  551.              ($def_option = $resolution_map{$defaults{$default_option}}) eq $opt)) { # Valid option
  552.             # Set the option in the new PPD
  553.             $source_data =~ s/\*($default_option).*/*$1:$def_option/m;
  554.             if ($verbose) {
  555.                 print "$ppd_source_filename: Set *$default_option to $def_option\n";
  556.             }
  557.             next default_loop;
  558.             }
  559.         }
  560.         warn "Warning: $ppd_source_filename: Invalid option: *$default_option: $defaults{$default_option}.  Using default setting.\n";
  561.         next;
  562.         }
  563.         warn "Warning: $ppd_source_filename: PPD OpenUI method $new_default_types{$default_option} not understood.\n";
  564.     }
  565.     }
  566.  
  567.     # Write new PPD...
  568.  
  569.     my $tmpnew = "${ppd_dest_filename}.new";
  570.     if (! open NEWPPD, "> $tmpnew") {
  571.     warn "Can't open $tmpnew for writing: $!\n";
  572.     return 0;
  573.     }
  574.     print NEWPPD $source_data;
  575.     if (! close NEWPPD) {
  576.     warn "Can't close ${tmpnew}.new for writing: $!\n";
  577.     unlink $tmpnew;
  578.     return 0;
  579.     }
  580.  
  581.     if (! rename $tmpnew, $ppd_dest_filename) {
  582.     warn "Can't rename $tmpnew to $ppd_dest_filename: $!\n";
  583.     unlink $tmpnew;
  584.     return 0;
  585.     }
  586.     chown($orig_metadata[4], $orig_metadata[5], $ppd_dest_filename);
  587.     chmod(($orig_metadata[2] & 0777), $ppd_dest_filename);
  588.  
  589.     if (!$quiet || $verbose) {
  590.     if ($ppd_dest_filename eq $ppd_source_filename) {
  591.         print STDOUT "Updated $ppd_source_filename using $new_ppd_filename\n";
  592.     } else {
  593.         print STDOUT "Updated $ppd_source_filename to $ppd_dest_filename using $new_ppd_filename\n";
  594.     }
  595.     }
  596.     return 1;
  597.     # All done!
  598. }
  599.  
  600. # Find a suitable source PPD file
  601. sub find_ppd ($$$$) {
  602.     my($gutenprintfilename, $drivername, $lang, $region) = @_;
  603.     my $file; # filename to return
  604.     my ($key) = '^\\*FileVersion:[     ]*"5.0.2"$';
  605.     my ($lingo, $suffix, $base, $basedir);
  606.     my ($current_best_file, $current_best_time);
  607.     my ($stored_name, $stored_dir, $simplified);
  608.     $stored_name = $gutenprintfilename;
  609.     $stored_name =~ s,.*/([^/]*)(.sim)?(.ppd)?(.gz)?$,$1,;
  610.     if ($gutenprintfilename =~ m,.*/([^/]*)(.sim)(.ppd)?(.gz)?$,) {
  611.     $simplified = ".sim";
  612.     } else {
  613.     $simplified = "";
  614.     }
  615.     $stored_dir = $gutenprintfilename;
  616.     $stored_dir =~ s,(.*)/([^/]*)$,$1,;
  617.  
  618.     $current_best_file = "";
  619.     $current_best_time = 0;
  620.  
  621.     # All possible candidates, in order of usefulness and gzippedness
  622.     foreach $lingo ("${lang}_${region}/",
  623.             "$lang/",
  624.             "en/",
  625.             "C/",
  626.             "") {
  627.     foreach $suffix (".ppd$gzext",
  628.              ".ppd") {
  629.         foreach $base ("${drivername}.$version${simplified}",
  630.                            "stp-${drivername}.$version${simplified}",
  631.                $stored_name,
  632.                $drivername) {
  633.         foreach $basedir ($ppd_base_dir,
  634.                   $stored_dir,
  635.                   $ppd_root_dir) {
  636.                     if (! $basedir || ! $base) { next; }
  637.             my ($fn) = "$basedir/$lingo$base$suffix";
  638.             if ($debug & 8) {
  639.                         print "Trying $fn for $gutenprintfilename, $lang, $region\n";
  640.                     }
  641. # Check that it is a regular file, owned by root.root, not writable
  642. # by other, and is readable by root.  i.e. the file is secure.
  643.             my @sb = stat $fn or next;
  644.             if (S_ISREG($sb[2]) && ($sb[4] == 0)) {
  645.             # Check that the file is a valid Gutenprint PPD file
  646.             # of the correct version.
  647.             my $file_version;
  648.             if ($fn =~ m/\.gz$/) {
  649.                 $file_version = `gunzip -c $fn | grep '$key'`;
  650.             } else {
  651.                 $file_version = `cat $fn | grep '$key'`;
  652.             }
  653.             if ($file_version ne "") {
  654.                             if ($debug & 8) {
  655.                     print "   Format valid: time $sb[9] best $current_best_time prev $current_best_file cur $fn!\n";
  656.                 }
  657.                 if ($sb[9] > $current_best_time) {
  658.                 $current_best_time = $sb[9];
  659.                 $current_best_file = $fn;
  660.                         if ($debug & 8) {
  661.                                     print STDERR "***current_best_file is $fn\n";
  662.                                 }
  663.                 }
  664.             } elsif ($debug & 8) {
  665.                 print "   Format invalid\n";
  666.             }
  667.             }
  668.             else {
  669.             $_ = $fn;
  670.             if (! -d $fn && ! /\/$/) {
  671.                 print STDERR "$fn: not a regular file, or insecure ownership and permissions.  Skipped\n";
  672.             }
  673.             }
  674.         }
  675.         }
  676.     }
  677.     }
  678.     if ($current_best_file) {
  679.         return $current_best_file;
  680.     }
  681. # Yikes!  Cannot find a valid PPD file!
  682.     return undef;
  683. }
  684.  
  685. # Return the default options from the given PPD filename
  686. sub get_default_types(*) {
  687.     my $fh = $_[0];
  688.     my %default_types;
  689.  
  690.     # Read each line of the original PPD file, and store all OpenUI
  691.     # names and their types in a hash...
  692.     seek ($fh, 0, 0) or die "can't seek to start of PPD file";
  693.     while (<$fh>) {
  694.     if ( m/^\*OpenUI/ ) {
  695.         chomp;
  696.         my ($key, $value) = /^\*OpenUI\s\*([[:alnum:]]+).*:\s([[:alnum:]]+)/;
  697.         if ($key && $value) {
  698.         $default_types{$key}=$value;
  699.         }
  700.     }
  701.     }
  702.     return %default_types;
  703. }
  704.  
  705.  
  706. # Return the default options from the given PPD filename
  707. sub get_resolution_map(*) {
  708.     my $fh = $_[0];
  709.     my %resolution_map;
  710.  
  711.     # Read each line of the original PPD file, and store all OpenUI
  712.     # names and their types in a hash...
  713.     seek ($fh, 0, 0) or die "can't seek to start of PPD file";
  714.     while (<$fh>) {
  715.     if ( m/^\*StpResolutionMap:/ ) {
  716.         chomp;
  717.         my ($junk, $new, $old) = split;
  718.         $resolution_map{$old} = $new;
  719.     }
  720.     }
  721.     return %resolution_map;
  722. }
  723.  
  724.  
  725. # Return the default options from the given PPD filename
  726. sub get_defaults(*) {
  727.     my $fh = $_[0];
  728.     my %defaults;
  729.  
  730.     # Read each line of the original PPD file, and store all default
  731.     # names and their values in a hash...
  732.     seek ($fh, 0, 0) or die "can't seek to start of PPD file";
  733.     while (<$fh>) {
  734.     if ( m/^\*Default/ ) {
  735.         chomp;
  736.         my($key, $value) = /^\*([[:alnum:]]+):\s*([[:alnum:]]+)/;
  737.         if ($key && $value) {
  738.         $defaults{$key}=$value;
  739.         }
  740.     }
  741.     }
  742.     return %defaults;
  743. }
  744.  
  745.  
  746. # Return the available options from the given PPD filename
  747. sub get_options(*\%) {
  748.     my $fh = $_[0];
  749.     my $validopts = $_[1];
  750.     my %options;
  751.  
  752.     # For each valid option name, grab each valid option for that name
  753.     # and store in a hash of arrays...
  754.  
  755.     foreach (sort keys %$validopts) {
  756.     my $tmp = $_;
  757.     my @optionlist;
  758.  
  759.     seek ($fh, 0, 0) or die "can't seek to start of PPD file";
  760.     while (<$fh>) {
  761.         if ( m/^\*$tmp/ ) {
  762.         chomp;
  763.         my ($value) = /^\*$tmp\s*([[:alnum:]]+)[\/:]/;
  764.         if ($value) {
  765.             push @optionlist, $value;
  766.         }
  767.         }
  768.     }
  769.     if (@optionlist) {
  770.         $options{$tmp} = [ @optionlist ];
  771.     }
  772.     }
  773.     return %options;
  774. }
  775.